package mdvrp;

import java.util.*;

public class CultureImproOperator {
	ArrayList<CultureImproPath> paths = new ArrayList<CultureImproPath>();
	public void clear() {
		this.paths.clear();
	}
	public void add(CultureImproPath path) {
		this.paths.add(path);
	}
	public CultureImproOperator crossover(CultureImproOperator operator, MDVRPCase data) {
		Random r = new Random();
		int x = r.nextInt(operator.paths.size());
		CultureImproOperator tmp_operator = new CultureImproOperator();
		Set<Integer> tmp_path_set = new HashSet<Integer>();
		for (int i = 0; i < operator.paths.get(x).orders.size(); i++) {
			tmp_path_set.add(operator.paths.get(x).orders.get(i));
		}
		x = r.nextInt(this.paths.size());
		for (int i = 0; i < this.paths.get(x).orders.size(); i++) {
			tmp_path_set.add(this.paths.get(x).orders.get(i));
		}
		for (int i = 0; i < this.paths.size(); i++) {
			CultureImproPath tmp_path = new CultureImproPath(this.paths.get(i).depot_id);
			for (int j = 0; j < this.paths.get(i).orders.size(); j++) {
				if (!tmp_path_set.contains(this.paths.get(i).orders.get(j))) {
					tmp_path.orders.add(this.paths.get(i).orders.get(j));
				}
			}
			tmp_operator.paths.add(tmp_path);
		}
		for (Integer key:tmp_path_set) {
			int best_path_pos = -1, best_order_pos = -1;
			double ans = -1;
			for (int j = 0; j < tmp_operator.paths.size(); j++) {
				if (tmp_operator.paths.get(j).orders.size() == 0) {
					double val = Checker.calc_delta_distance(data, key, tmp_operator.paths.get(j).depot_id);
					if (ans < 0 || ans > val) {
						ans = val;
						best_path_pos = j;
						best_order_pos = 0;
					}
				}else{
					for (int k = 1; k < tmp_operator.paths.get(j).orders.size(); k++) {
						double val = Checker.calc_delta_distance(data, key, tmp_operator.paths.get(j).orders.get(k), tmp_operator.paths.get(j).orders.get(k - 1));
						if (ans < 0 || ans > val) {
							ans = val;
							best_path_pos = j;
							best_order_pos = k;
						}
					}
					double val = Checker.calc_delta_distance(data, key, tmp_operator.paths.get(j).orders.get(0), tmp_operator.paths.get(j).depot_id, 1);
					if (ans < 0 || ans > val) {
						ans = val;
						best_path_pos = j;
						best_order_pos = 0;
					}
					val = Checker.calc_delta_distance(data, key, tmp_operator.paths.get(j).orders.get(tmp_operator.paths.get(j).orders.size() - 1), tmp_operator.paths.get(j).depot_id, 1);
					if (ans < 0 || ans > val) {
						ans = val;
						best_path_pos = j;
						best_order_pos = tmp_operator.paths.get(j).orders.size();
					}
				}
			}
			tmp_operator.paths.get(best_path_pos).orders.add(best_order_pos, key);
		}
		return tmp_operator;
	}
	public CultureImproOperator mutation() {
		Random r = new Random();
		int x = r.nextInt(this.paths.size());
		CultureImproOperator operator = this.copy();
		int y = r.nextInt(this.paths.get(x).orders.size());
		int z = r.nextInt(this.paths.get(x).orders.size());
		int tmp_y = this.paths.get(x).orders.get(y);
		int tmp_z = this.paths.get(x).orders.get(z);
		operator.paths.get(x).orders.set(y, tmp_z);
		operator.paths.get(x).orders.set(z, tmp_y);
		return operator;
	}
	public CultureImproOperator copy() {
		CultureImproOperator new_operator = new CultureImproOperator();
		for (int i = 0; i < this.paths.size(); i++) {
			new_operator.paths.add(this.paths.get(i).copy());
		}
		return new_operator;
	}
	public void print() {
		System.out.println("Operator: path_size " + this.paths.size());
		for (int i = 0; i < this.paths.size(); i++) {
			this.paths.get(i).print();
		}
	}
	public static void main(String args[]) {
		MDVRPDataSet dataset = new MDVRPDataSet();
		dataset.cases.get(0).print();
		CultureImproOperator operator1 = new CultureImproOperator();
		CultureImproPath path = null;
		for (int i = 1; i <= 50; i++) {
			if (i % 6 == 1) {
				if (i != 1) {
					operator1.paths.add(path);
				}
				path = new CultureImproPath();
				path.depot_id = i / 14 + 1;
				path.orders = new ArrayList<Integer>();
			}
			path.orders.add(i);
		}
		operator1.paths.add(path);
		System.out.println("mutation test");
		operator1.print();
		operator1 = operator1.mutation();
		operator1.print();
		System.out.println();
		
		System.out.println("crossover test");
		CultureImproOperator operator2 = operator1.copy();
		operator2.print();
		CultureImproOperator new_operator = operator1.crossover(operator2, dataset.cases.get(0));
		new_operator.print();
	}
}
